package cn.kkcxy.blog.system.service.impl.article;

import cn.kkcxy.blog.common.constant.ExceptionMessageConstant;
import cn.kkcxy.blog.core.dto.client.ClientArticleCategoryQueryParamsDTO;
import cn.kkcxy.blog.core.dto.client.ClientArticleTagsRequestDTO;
import cn.kkcxy.blog.core.entity.article.Article;
import cn.kkcxy.blog.core.entity.article.ArticleCategory;
import cn.kkcxy.blog.core.enums.ArticleCategoryEnum;
import cn.kkcxy.blog.core.enums.DeletedEnum;
import cn.kkcxy.blog.core.exception.article.ArticleCategoryServiceException;
import cn.kkcxy.blog.core.vo.client.archive.ClientArticleArchiveVO;
import cn.kkcxy.blog.core.vo.client.archive.ClientArticleVO;
import cn.kkcxy.blog.core.vo.client.archive.category.ClientArticleCategoryParentInfoVO;
import cn.kkcxy.blog.core.vo.client.archive.category.ClientArticleCategoryVO;
import cn.kkcxy.blog.core.vo.client.archive.category.ClientFirstLevelArticleCategoryVO;
import cn.kkcxy.blog.core.vo.client.archive.tag.ClientArticleTagsInfoVO;
import cn.kkcxy.blog.core.vo.client.archive.tag.ClientArticleTagsVO;
import cn.kkcxy.blog.system.mapper.article.ArticleCategoryMapper;
import cn.kkcxy.blog.system.mapper.article.ArticleCategoryMappingMapper;
import cn.kkcxy.blog.system.mapper.article.ArticleMapper;
import cn.kkcxy.blog.system.mapper.article.ArticleTagMapper;
import cn.kkcxy.blog.system.service.article.ArticleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author kk
 * @description 针对表【article】的数据库操作Service实现
 * @createDate 2024-09-18 00:25:54
 */
@Slf4j
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    /**
     * Article Mapper
     */
    @Resource
    private ArticleMapper articleMapper;

    /**
     * Article Category Mapper
     */
    @Resource
    private ArticleCategoryMapper articleCategoryMapper;

    /**
     * Article Category Mapping Mapper
     */
    @Resource
    private ArticleCategoryMappingMapper articleCategoryMappingMapper;

    /**
     * Article Tag Mapper
     */
    @Resource
    private ArticleTagMapper articleTagMapper;

    /**
     * Archive ThreadPool
     */
    @Resource
    private ThreadPoolExecutor archiveThreadPool;

    /**
     * @description: [用户端] 获取文章归档数据
     * @author: kkcxy
     * @date: 2024/9/18 1:57
     * @param: []
     * @return: cn.kkcxy.blog.core.vo.client.archive.ClientArticleArchiveVO
     **/
    @SneakyThrows
    @Override
    public List<ClientArticleArchiveVO> getArticleArchiveData() {
        // 结果集
        List<ClientArticleArchiveVO> vo = new ArrayList<>();
        // 获取文章归档的日期列表
        List<String> archiveDate = articleMapper.getArticleArchiveDate();
        // 查询出的日期如果为空直接返回一个空集合
        if (CollectionUtils.isEmpty(archiveDate)) {
            return Collections.emptyList();
        }
        // 查询文章列表数据
        for (String date : archiveDate) {
            // 创建结果 VO 类
            ClientArticleArchiveVO clientArticleArchiveVO = new ClientArticleArchiveVO();
            // 查询 文章列表数据
            CompletableFuture<List<ClientArticleVO>> boList =
                    CompletableFuture.supplyAsync(() -> articleMapper.getArticleListByDate(date), archiveThreadPool);
            // 设置 日期
            clientArticleArchiveVO.setDate(date);
            // 设置 对应日期的文章列表数据
            clientArticleArchiveVO.setArticleList(boList.get());
            vo.add(clientArticleArchiveVO);
        }
        return vo;
    }

    /**
     * @description: [用户端] 获取文章分类列表数据
     * @author: kkcxy
     * @date: 2024/9/19 2:14
     * @param: [clientArticleCategoryQueryParamsDTO]
     * @return: java.util.List<cn.kkcxy.blog.core.vo.client.archive.category.ClientArticleCategoryVO>
     **/
    @SneakyThrows
    @Override
    public ClientArticleCategoryVO getArticleCategoryListData(ClientArticleCategoryQueryParamsDTO clientArticleCategoryQueryParamsDTO) {
        // 构建结果集
        ClientArticleCategoryVO clientArticleCategoryVO = new ClientArticleCategoryVO();
        // 判断一级分类是否为空
        boolean primaryCategoryIsNull = StringUtils.isEmpty(clientArticleCategoryQueryParamsDTO.getPrimaryCategory());
        // 判断二级分类是否为空
        boolean secondLevelCategoryIsNull = CollectionUtils.isEmpty(clientArticleCategoryQueryParamsDTO.getSecondLevelCategoryList());
        // 进入业务处理
        // 如果一二级分类都为空的话 查询出文章分类列表
        if (primaryCategoryIsNull && secondLevelCategoryIsNull) {
            log.info("处理 [分类参数为空] 业务");
            // 得到文章分类列表
            List<ClientFirstLevelArticleCategoryVO> categoryList = articleCategoryMapper.getArticleCategoryListData();
            // 设置 分类列表
            clientArticleCategoryVO.setCategoryList(categoryList);
        } else if (primaryCategoryIsNull) {
            // 直接抛异常 不符合业务规则 一级分类为空 二级分类有值
            log.error("原因：[不符合业务规则 一级分类为空 二级分类有值]");
            throw new ArticleCategoryServiceException(ExceptionMessageConstant.GET_ARTICLE_CATEGORY_OR_ARTICLE_LIST_ERROR);
        } else {
            // 查出一级分类的数据
            Long categoryId = articleCategoryMapper.getCategoryIdByCategoryName(
                    clientArticleCategoryQueryParamsDTO.getPrimaryCategory(), DeletedEnum.NO.getStatus()
            );
            // 如果分类Id为空，抛出异常
            if (ObjectUtils.isEmpty(categoryId)) {
                log.error("原因：[一级分类不存在]");
                throw new ArticleCategoryServiceException(ExceptionMessageConstant.GET_ARTICLE_CATEGORY_OR_ARTICLE_LIST_UPDATED);
            }
            // 存储二级分类Id TODO Bug
            List<Long> ids = new ArrayList<>();
            if (secondLevelCategoryIsNull) {
                // 二级分类为空 查出该一级分类下所有的文章数据
                ids = articleCategoryMapper.getSecondLevelCategoryIdsByPrimaryCategoryId(categoryId);
            } else {
                // 不为空 仅查询二级分类文章数据
                ids = articleCategoryMapper.getSecondLevelCategoryIdsBySecondLevelCategoryName(clientArticleCategoryQueryParamsDTO.getSecondLevelCategoryList());
            }
            // 如果二级分类为空，直接返回一个空集合
            if (CollectionUtils.isEmpty(ids)) {
                clientArticleCategoryVO.setArticleList(Collections.emptyList());
            } else {
                // 如果是一级分类需要将一级分类id也放入查询条件集合中 一级分类也可以有文章数据
                ids.add(categoryId);
                // 获取需要查询数据的文章ids
                List<Long> articleIds = articleCategoryMappingMapper.getArticleIdsListByCategoryIds(ids);
                // 如果文章Id为空，直接返回一个空集合 （基本不太可能出现 除非数据库数据异常）
                if (CollectionUtils.isEmpty(articleIds)) {
                    clientArticleCategoryVO.setArticleList(Collections.emptyList());
                } else {
                    // 创建文章结果集
                    List<ClientArticleVO> articleList = new ArrayList<>();
                    // 多线程去查
                    for (Long id : articleIds) {
                        CompletableFuture<ClientArticleVO> clientArticleVO =
                                CompletableFuture.supplyAsync(() -> articleMapper.getArticleVOById(id), archiveThreadPool);
                        // 拿到结果
                        ClientArticleVO articleVO = clientArticleVO.get();
                        articleList.add(articleVO);
                    }
                    // 设置 文章列表
                    clientArticleCategoryVO.setArticleList(articleList);
                }
            }
        }
        // 返回结果
        return clientArticleCategoryVO;
    }

    /**
     * @description: [用户端] 获取文章标签列表数据
     * @author: kkcxy
     * @date: 2024/9/21 0:37
     * @param: [clientArticleTagsRequestDTO]
     * @return: cn.kkcxy.blog.core.vo.client.archive.tag.ClientArticleTagsVO
     **/
    @Override
    public ClientArticleTagsVO getArticleTagsListOrArticleList(ClientArticleTagsRequestDTO clientArticleTagsRequestDTO) {
        // 构建结果集
        ClientArticleTagsVO clientArticleTagsVO = new ClientArticleTagsVO();
        // 参数
        List<String> dtoTags = clientArticleTagsRequestDTO.getTags();
        // 条件标签列表为空的情况
        if (CollectionUtils.isEmpty(dtoTags)) {
            // 查询出所有的标签
            List<ClientArticleTagsInfoVO> tagList = articleTagMapper.selectTagList();
            clientArticleTagsVO.setTagList(tagList);
        } else {
            // 获取参数标签的id集合
            List<Long> ids = articleTagMapper.selectArticleTagIdsByTagName(dtoTags);
            // 如果查出来为空 直接返回空
            if (CollectionUtils.isEmpty(ids)) {
                clientArticleTagsVO.setArticleList(Collections.emptyList());
                return clientArticleTagsVO;
            }
//             获取文章列表
            List<ClientArticleVO> articleList = articleMapper.selectArticleListByTagIds(ids);
            clientArticleTagsVO.setArticleList(articleList);
        }
        return clientArticleTagsVO;
    }

    /**
     * @description: [用户端] 获取父级分类信息根据分类名称
     * @author: kkcxy
     * @date: 2024/9/24 0:51
     * @param: [categoryName]
     * @return: cn.kkcxy.blog.core.vo.client.archive.category.ClientArticleCategoryParentInfoVO
     **/
    @Override
    public ClientArticleCategoryParentInfoVO getArticleCategoryParentInfoByCategoryName(String categoryName) {
        // 构建结果集
        ClientArticleCategoryParentInfoVO vo = new ClientArticleCategoryParentInfoVO();
        // 判断参数是否为空
        if (ObjectUtils.isEmpty(categoryName)) {
            throw new ArticleCategoryServiceException(ExceptionMessageConstant.ARTICLE_CATEGORY_IS_NULL_ERROR);
        }
        // 去除多余空格 防止参数异常
        String category = categoryName.trim();
        // 构建查询参数
        LambdaQueryWrapper<ArticleCategory> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.eq(ArticleCategory::getCategoryName, category);
        // 得到分类信息
        ArticleCategory categoryInfo = articleCategoryMapper.selectOne(categoryWrapper);
        // 如果为空
        if (ObjectUtils.isEmpty(categoryInfo)) {
            throw new ArticleCategoryServiceException(ExceptionMessageConstant.ARTICLE_CATEGORY_INFO_IS_NULL_ERROR);
        }
        // 判断分类等级
        if (Objects.equals(ArticleCategoryEnum.PRIMARY.getType(), categoryInfo.getCategoryType())) {
            // 一级分类
            vo.setCategoryName(categoryName);
            vo.setPrimary(true);
        } else {
            // 二级分类
            vo.setPrimary(false);
            if (ObjectUtils.isEmpty(categoryInfo.getCategoryParent())) {
                throw new ArticleCategoryServiceException(ExceptionMessageConstant.ARTICLE_CATEGORY_INFO_IS_NULL_ERROR);
            }
            String categoryParentName = articleCategoryMapper.getCategoryNameByCategoryId(categoryInfo.getCategoryParent(), DeletedEnum.NO.getStatus());
            vo.setCategoryName(categoryParentName);
        }
        return vo;
    }

    /**
     * @description: 得到文章总数
     * @author: kkcxy
     * @date: 2024/9/28 23:28
     * @param: []
     * @return: java.lang.Integer
     **/
    @Override
    public Integer getArticleCount() {
        return articleMapper.getArticleCount();
    }

}
